import React from 'react'
import { autorun, makeAutoObservable, observable, action, reaction, makeObservable, configure } from 'mobx'
import { observer } from 'mobx-react-lite'
// import { observer } from 'mobx-react'

// mobx 的全局配置
configure({
  // 强制使用 action 方法的模式去修改状态，不允许单独基于实例修改状态
  enforceActions: 'observed'
})

const nums = observable({
  num: 10,
  increment: action(function () {
    this.num++
  }),

  // 计算属性：
  get getDouble() {
    return this.num * 2
  }
})

autorun(() => {
  console.log('autorun发生了', nums.num)
  console.log('autorun发生了，计算属性双倍num', nums.getDouble)
})

class TestStore {
  counter = 0

  constructor() {
    makeObservable(this, {
      counter: observable,
      addCounter: action,
      subCounter: action
    })
  }

  addCounter() {
    this.counter++
  }

  subCounter() {
    this.counter--
  }
}

const testStore = new TestStore()

autorun(() => {
  console.log('testStore的autorun发生了', testStore.counter)
})

// 创建一个容器
class Store {
  // 公共状态
  // @observable 是指当前状态可以被监听
  // @observable count = 100
  // count = observable.box(100)
  count = 100

  // 使用 makeObservable 或 makeAutoObservable 绑定之后才是真的state
  constructor() {
    makeAutoObservable(this, {}, { autoBind: true })
  }

  // computed：装饰器，创建一个具备计算缓存的计算属性
  // @computed get doubleCount() {
  //   console.log('doubleCount计算属性执行')
  //   return this.count * 2
  // }

  // 修改公共状态（他可以让函数中的状态更改变为异步批处理，即可以在这里修改多个值，当全部修改完之后才会执行 autorun 监听，而不是修改一个触发一次）：
  /**
   * 推荐加上 .bound 后缀，因为当把这个方法赋值给其他变量后，这个里面的 this 就变成了 undefined，为了避免这种情况，推荐加 .bound
   * 即：
   * 在其他地方进行：
   * let func = state.addCount
   * func() // 这个时候，引用的方法里的 this 就变成了 undefined，但是加上 .bound 后缀之后就变成了原本指代的 Store 实例
   *
   */
  // @action.bound addCount() {
  //   this.count++
  //   console.log('addCount 执行，加一', this.count)
  // }
  addCount() {
    this.count++
    console.log('addCount 执行，加一', this.count)
  }
}

let store = new Store()

// 首先会立即执行一次，自动建立依赖监测（监测用到的状态），当依赖的值发生改变，回调函数会重新执行
autorun(() => {
  console.log('autorun', store.count)
})

// 和 autorun 一样，都是监听器，提供更细粒化的状态监测，但是默认首次不执行
reaction(
  // 指定检测：
  () => [store.count, nums.increment],
  () => {
    console.log('reaction执行', store.count, nums.increment)
  }
)

// 这里使用类组件不太行
// @observer
// export class MobxDemo extends PureComponent {
//   render() {
//     const { count } = store
//     return (
//       <div>
//         <div>mobx 计数器：{count}</div>
//         <button onClick={() => store.addCount()}>点击 +1</button>
//         <div>num:{nums.num}</div>
//         <div>双倍的num：{nums.getDouble}</div>
//         <button onClick={() => nums.increment()}>点击 +1</button>
//         <hr />
//         <div>counter:{testStore.counter}</div>
//         <button onClick={() => testStore.addCounter()}>加一</button>
//         <button onClick={() => testStore.subCounter()}>减一</button>
//       </div>
//     )
//   }
// }

export const MobxDemo = observer(() => {
  const { count } = store
  return (
    <div>
      <div>mobx 计数器：{count}</div>
      <button onClick={() => store.addCount()}>点击 +1</button>
      <div>num：{nums.num}</div>
      <div>双倍的num：{nums.getDouble}</div>
      <button onClick={() => nums.increment()}>点击 +1</button>
      <p />
      <div>counter：{testStore.counter}</div>
      <button onClick={() => testStore.addCounter()}>加一</button>
      <button onClick={() => testStore.subCounter()}>减一</button>
    </div>
  )
})

export default MobxDemo
